//
//  GCDQueue.m
//  MyFunctionDemo
//
//  Created by Ting Han on 2017/8/28.
//  Copyright © 2017年 Ting Han. All rights reserved.
//

#import "GCDQueue.h"
#import "GCDGroup.h"
#import "GCDSemaphore.h"

static GCDQueue *mainQueue;
static GCDQueue *lowPriorityGlobalQueue;
static GCDQueue *highPriorityGlobalQueue;
static GCDQueue *globalQueue;
static GCDQueue *backgroundPriorityGlobalQueue;

@interface GCDQueue ()

@property (nonatomic,strong) dispatch_queue_t dispatchQueue;

@end
@implementation GCDQueue

#pragma mark --- 获取线程
+ (instancetype)mainQueue{
    return mainQueue;
}
+ (instancetype)globalQueue{
    return globalQueue ;
}
+ (instancetype)lowPriorityGlobalQueue{
    return lowPriorityGlobalQueue;
}
+ (instancetype)highPriorityGlobalQueue{
    return highPriorityGlobalQueue;
}
+ (instancetype)backgroundPriorityGlobalQueue{
    return backgroundPriorityGlobalQueue;
}
+ (void)initialize
{
    if (self == [GCDQueue class]) {
        mainQueue = [GCDQueue new];
        lowPriorityGlobalQueue = [GCDQueue new];
        highPriorityGlobalQueue = [GCDQueue new];
        globalQueue = [GCDQueue new];
        backgroundPriorityGlobalQueue = [GCDQueue new];
        mainQueue.dispatchQueue = dispatch_get_main_queue();
        globalQueue.dispatchQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        lowPriorityGlobalQueue.dispatchQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0);
        highPriorityGlobalQueue.dispatchQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
        backgroundPriorityGlobalQueue.dispatchQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0);
        
    }
}
#pragma mark --- 初始化线程
- (instancetype)init{
    return [self initSerial];
}
//串行队列
- (instancetype)initSerial
{
    self = [super init];
    if (self) {
        self.dispatchQueue = dispatch_queue_create(nil, DISPATCH_QUEUE_SERIAL);
    }
    return self;
}
- (instancetype)initSerialWithIdentifier:(NSString *)identifier{
    self = [super init];
    if (self) {
        self.dispatchQueue = dispatch_queue_create(identifier.UTF8String, DISPATCH_QUEUE_SERIAL);
    }
    return self;
}
- (instancetype)initConcurrent{
    self = [super init];
    if (self) {
        self.dispatchQueue = dispatch_queue_create(nil, DISPATCH_QUEUE_CONCURRENT);
    }
    return self;
}
- (instancetype)initConcurrentWithIdentifier:(NSString *)identifier{
    self = [super init];
    if (self) {
        self.dispatchQueue = dispatch_queue_create(identifier.UTF8String, DISPATCH_QUEUE_CONCURRENT);
    }
    return self;
}
#pragma mark --- 便利构造器
+ (void)executeInMainQueue:(dispatch_block_t)block afterDelaySecs:(NSTimeInterval)sec{
    NSParameterAssert(block);
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * sec), mainQueue.dispatchQueue, block);
}
+ (void)executeInGlobalQueue:(dispatch_block_t)block afterDelaySecs:(NSTimeInterval)sec {
    
    NSParameterAssert(block);
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * sec), globalQueue.dispatchQueue, block);
}

+ (void)executeInHighPriorityGlobalQueue:(dispatch_block_t)block afterDelaySecs:(NSTimeInterval)sec {
    
    NSParameterAssert(block);
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * sec), highPriorityGlobalQueue.dispatchQueue, block);
}

+ (void)executeInLowPriorityGlobalQueue:(dispatch_block_t)block afterDelaySecs:(NSTimeInterval)sec {
    
    NSParameterAssert(block);
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * sec), lowPriorityGlobalQueue.dispatchQueue, block);
}

+ (void)executeInBackgroundPriorityGlobalQueue:(dispatch_block_t)block afterDelaySecs:(NSTimeInterval)sec {
    
    NSParameterAssert(block);
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * sec), backgroundPriorityGlobalQueue.dispatchQueue, block);
}

+ (void)executeInMainQueue:(dispatch_block_t)block {
    
    NSParameterAssert(block);
    dispatch_async(mainQueue.dispatchQueue, block);
}

+ (void)executeInGlobalQueue:(dispatch_block_t)block {
    
    NSParameterAssert(block);
    dispatch_async(globalQueue.dispatchQueue, block);
}

+ (void)executeInHighPriorityGlobalQueue:(dispatch_block_t)block {
    
    NSParameterAssert(block);
    dispatch_async(highPriorityGlobalQueue.dispatchQueue, block);
}

+ (void)executeInLowPriorityGlobalQueue:(dispatch_block_t)block {
    
    NSParameterAssert(block);
    dispatch_async(lowPriorityGlobalQueue.dispatchQueue, block);
}

+ (void)executeInBackgroundPriorityGlobalQueue:(dispatch_block_t)block {
    
    NSParameterAssert(block);
    dispatch_async(backgroundPriorityGlobalQueue.dispatchQueue, block);
}

#pragma mark --- 操作
- (void)execute: (dispatch_block_t)block
{
    NSParameterAssert(block);
    dispatch_async(self.dispatchQueue, block);
}

- (void)execute: (dispatch_block_t)block delay: (NSTimeInterval)delay
{
    NSParameterAssert(block);
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, delay * NSEC_PER_SEC), self.dispatchQueue, block);
}
- (void)execute: (dispatch_block_t)block wait: (GCDSemaphore *)semaphore
{
    NSParameterAssert(block);
    dispatch_block_t executeBlock = ^{
        [semaphore wait];
        block();
        [semaphore signal];
    };
    dispatch_async(self.dispatchQueue, executeBlock);
}

- (void)execute: (dispatch_block_t)block delay: (NSTimeInterval)delay wait: (GCDSemaphore *)semaphore
{
    NSParameterAssert(block);
    dispatch_block_t executeBlock = ^{
        [semaphore wait];
        block();
        [semaphore signal];
    };
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, delay * NSEC_PER_SEC), self.dispatchQueue, executeBlock);
}


- (void)resume
{
    dispatch_resume(self.dispatchQueue);
}

- (void)suspend
{
    dispatch_suspend(self.dispatchQueue);
}

- (void)barrierExecute: (dispatch_block_t)block
{
    NSParameterAssert(block);
    dispatch_barrier_async(self.dispatchQueue, block);
}
- (void)notify:(dispatch_block_t)block inGroup:(GCDGroup *)group{
    NSParameterAssert(block);
    dispatch_group_notify(group.dispatchGroup, self.dispatchQueue, block);

}
- (void)execute:(dispatch_block_t)block inGroup:(GCDGroup *)group{
    NSParameterAssert(block);
    dispatch_group_async(group.dispatchGroup, self.dispatchQueue, block);
}


@end
